About Event Handling in OpenDoc
Your OpenDoc part editor is required to respond to a specific set of actions or messages from OpenDoc that, although generated and passed in different ways on different platforms, constitute the majority of user interactions with your parts. In OpenDoc, these messages are called user events.User events in OpenDoc include mouse clicks and keystrokes, menu commands, activation and deactivation of windows, and other events available only on some platforms. This section defines the different types of events and discusses how your part editor's
HandleEvent
method handles them.How User Events Are Handled
The document shell receives platform-specific events through whatever event-
delivery mechanism the underlying platform provides. The shell converts them into the form of OpenDoc user events and passes them to the dispatcher by calling itsDispatch
method. The dispatcher handles the events it recognizes, using a dispatch module to pass events to individual parts. TheDispatch
method returns all other events, as well as events passed to parts but not handled by them, to the document shell to handle.When the OpenDoc dispatcher receives an event intended for your part, it locates a dispatch module for the event. The dispatch module in turn calls your part's
HandleEvent
method. (Your part'sDraw
method can be called indirectly because of an event, through theUpdate
method of a window or facet.)Your part becomes the target for a specific type of user event (other than geometry-based events) by obtaining the focus for that event. The OpenDoc arbitrator keeps track of which part owns which foci by consulting a focus module, which tracks, for example, which part is currently active and therefore should receive keystroke events. Foci and focus modules are described further in the section "Focus Types".
Geometry-based events, such as mouse clicks, are generally dispatched to the parts within whose frames they occur, regardless of which part currently has the selection focus--that is, regardless of which part is currently active. This permits inside-out activation to occur.
Your part receives some of the information about its events in a platform-specific event structure. On the Mac OS platform, the event structure is equivalent to an event record. This is its definition:
struct ODEventData { short what; long message; long when; Point where; short modifiers; };Other information about the event is passed to your part (on the Mac OS platform) in an OpenDoc-defined event-info structure:
struct ODEventInfo { ODFrame embeddedFrame; ODFacet embeddedFacet; ODPoint where; ODBoolean propagated; };For any geometry-based event (mouse event) that is passed to your part, the coordinates of the event are passed in thewhere
field of the structure. For events in embedded frames that are passed to your part, the frame and facet within which the event occurred are passed in theembeddedFrame
andembeddedFacet
fields.Types of User Events
On the Mac OS platform, your parts must in general handle the types of user events listed in Table 5-1. Not all of these events exist on all other platforms.
Table 5-1 OpenDoc user events (Mac OS platform) Standard Mac OS events OpenDoc-defined events kODEvtNull kODEvtMenu kODEvtMouseDown kODEvtWindow kODEvtMouseUp kODEvtMouseEnter kODEvtKeyDown kODEvtMouseWithin kODEvtKeyUp kODEvtMouseLeave kODEvtAutoKey kODEvtBGMouseDown kODEvtUpdate kODEvtMouseDownBorder[4] kODEvtActivate kODEvtMouseDownEmbedded[4] kODEvtOS kODEvtMouseUpEmbedded[4] kODEvtBGMouseDownEmbedded[4] The following sections describe how you handle each of these kinds of events.
Mouse Events
When the user presses or releases the mouse button while the mouse pointer is in the content area of an OpenDoc window, the dispatcher finds the correct part to handle the mouse event by traversing the hierarchy of facets in the window.The dispatcher searches depth-first (trying the most deeply embedded facets first) and front-to-back (trying the frontmost of sibling facets first). The dispatcher sends the event to the editor of the first--that is, most deeply embedded and frontmost--frame it finds whose active shape contains the pointer position. In this way the smallest enclosing frame surrounding the pointer location receives the mouse event, preserving the OpenDoc inside-out activation model. None of the part editors of any containing parts in that frame's embedding hierarchy are involved in handling the event.
When the user presses a mouse button while the pointer is within a facet of your part, the dispatcher calls your part's
HandleEvent
method, passing it an event type ofkODEvtMouseDown
. (If your part is in a document in a background process on the Mac OS, the dispatcher passes yourHandleEvent
method an event type ofkODEvtBGMouseDown
.)When the user releases the mouse button while the pointer is within your facet, the dispatcher again calls your part's
HandleEvent
method, this time passing it an event type ofkODEvtMouseUp
.The event-dispatching code does not itself activate and deactivate the relevant parts; it is up to the editor of the part receiving the mouse event to decide whether to activate itself or not. See the section "Mouse Events, Activation, and Dragging" for information on how your part should handle mouse-down and mouse-up events within its facets for the purposes of part activation, window activation, and drag and drop.
The dispatcher also tracks pointer position at all times when the mouse button is not pressed.
You can use these events to, for example, change the cursor appearance. See "Mouse-Up Tracking".
- When the pointer enters a facet of your part, the dispatcher calls your part's
HandleEvent
method, passing it an event type ofkODEvtMouseEnter
.- Whenever the pointer moves within your facet, the dispatcher calls your part's
HandleEvent
method, passing it an event type ofkODEvtMouseWithin
.- When the pointer leaves your facet, the dispatcher calls your part's
HandleEvent
method, passing it an event type ofkODEvtMouseLeave
.
In some situations in the Mac OS platform, OpenDoc redirects or changes mouse events:
Mouse clicks within controls associated with your part can be handled in a number of ways, as discussed in the section "Controls".
- If the user holds down the Shift key or Command key while pressing or releasing the mouse button, the dispatcher instead sends the event to the frame with the selection focus. This allows users to extend selections by Shift-clicking or Command-clicking.
- If the mouse event is in the title bar or resize box of a window, the dispatcher converts it to a window event.
- If the mouse event is in the menu bar, the dispatcher converts it to a menu event.
- If a frame has ), mouse events that occur outside of its border are sent to it. However, mouse events that occur within frames embedded within the frame with the modal focus are sent to the embedded frames, as expected.
- If a frame has the mouse focus (see "Mouse-Up Feedback While Drawing"), it receives all mouse-within events that occur, regardless of their location.
Mouse Events in Embedded Frames
If your part contains embedded frames, the dispatcher can also send you special mouse events that occur within and on the borders of the embedded frames' facets.The following events occur when your part's frame is the active frame and the embedded frame is selected or bundled or in icon view type, or if the user Shift-clicks or Command-clicks in the embedded frame to extend a selection:
The following event occurs when the frame embedded within your part is the active frame:
- When the user presses a mouse button while the pointer is within a facet of the embedded frame, the dispatcher calls your part's
HandleEvent
method, passing it an event type ofkODEvtMouseDownEmbedded
. (If your part is in a document in a background process on the Mac OS, the dispatcher passes yourHandleEvent
method an event type ofkODEvtBGMouseDownEmbedded
.)- When the user releases a mouse button while the pointer is within the embedded facet, the dispatcher again calls your part's
HandleEvent
method, this time passing it an event type ofkODEvtMouseUpEmbedded
.There is one exception to this. If the embedded frame is selected (rather than bundled or in icon view type), and if the mouse-up is not part of a Shift-click or Command-click, your part does not receive the mouse-up event. In such a case, if the user initiates a drag the mouse-up event is converted to a drop; if the user does not initiate a drag, the mouse-up event is sent to the embedded frame so that it can activate itself. See "Mouse Events, Activation, and Dragging" for more information, including how to handle events in a background process.
These events allow your part to activate itself and select or drag the embedded part.
- When the user presses the mouse button while the pointer is within the active border of a facet of the embedded frame, the dispatcher calls your part's
HandleEvent
method, passing it an event type ofkODEvtMouseDownBorder
.
Keystroke Events
When the user presses a key on the keyboard and your part has the keystroke focus, the dispatcher calls your part'sHandleEvent
method, passing it an event type ofkODEvtKeyDown
. When the user releases the key, the dispatcher again calls your part'sHandleEvent
method, this time passing it an event type ofkODEvtKeyUp
.Exceptions to this convention include keystroke events that are keyboard equivalents to menu commands, which go to your part as menu events, and keystroke events involving the Page Up, Page Down, Home, and End keys, which go to the frame--if any--that has the scrolling focus.
Menu Events
If the user presses the mouse button when the pointer is within the menu bar, or if the user enters a keyboard equivalent to that action, OpenDoc converts the mouse-down or keystroke event into a menu event of typekODEvtMenu
and calls theHandleEvent
method of the part with the menu focus.On the Mac OS platform, the
message
field of the event structure passed toHandleEvent
specifies the menu and item selected, equivalent to the results of calling theMenuSelect
orMenuKey
function of the Menu Manager. In addition, theHandleEvent
method can obtain a command ID for the menu event by calling theGetCommand
method of the menu bar object.Handling individual menu commands is discussed in the section "Menus"
Window Events
If the user presses the mouse button while the pointer is within a noncontent portion of the window (such as the close box in the title bar of a Mac OS window), or if the user enters a keyboard equivalent to that action, OpenDoc converts the mouse-down or keystroke event into an event of typekODEvtWindow
and calls theHandleEvent
method of the window's root part.If the root part does not handle the event, the dispatcher returns it to the document shell, which performs the intended action (such as closing the window). However, if your part is the root part it can handle the event if it wishes. For example, it might hide the window rather than closing it.
For window events, the
message
field of the event structure contains the part code--equivalent to the results of the Mac OSFindWindow
function--describing the part of the window, such as the close box, in which the event occurred.How to handle window events when your part is the root part is described in the section "Handling Window Events".
Activate Events
On platforms such as Mac OS that support activation and deactivation of windows, OpenDoc sends activate events and deactivate events, of typekODEvtActivate
, to each facet in the window when the window changes state.If the user clicks in the title bar of an inactive Mac OS window, OpenDoc activates the window and brings it to the front. If the user clicks in the content area of an inactive window, the part at the click location brings the window to the front. Either way, when an active Mac OS window becomes inactive because another Mac OS window has become active, each facet of each part displayed in the window being deactivated receives a deactivate event, and each facet of each part displayed in the window being activated receives an activate event.
Your part's
HandleEvent
method can use these events to store and retrieve information that allows your part to decide whether or not to activate itself when its window becomes active. See "Handling Activate Events" for an explanation.Update Events
To support redrawing of previously invalidated areas of a window, frame, or facet, OpenDoc handles update events and calls theDraw
methods of the appropriate parts.Update events are themselves triggered by the existence of invalid areas, created through changes to the content of parts, the activation of windows, or the removal of obscuring objects such as floating windows.
OpenDoc does not pass update events to your
HandleEvent
method. When an update event occurs that involves a facet of your part, the dispatcher calls theUpdate
method of the window, which results in a call to yourDraw
method. For more information, see the section "Invalidating and Updating".Null Events
On platforms such as the Mac OS that support the concept of idle time, OpenDoc permits your part to receive idle-time events, also called null events (typekODEvtNull
). To receive null events, your part must first call theRegisterIdle
method of the dispatcher to register each frame that is to receive null events. When you callRegisterIdle
, you specify an idle frequency. OpenDoc uses the idle frequency to compute the sleep time it passes toWaitNextEvent
.Your call to the
RegisterIdle
method might occur in your part'sDisplayFrameAdded
,DisplayFrameConnected
, orFacetAdded
methods. You should unregister any idle frames (using the dispatcher'sUnregisterIdle
method) before the frames are deleted. You might make the call in your
part'sDisplayFrameClosed
andDisplayFrameRemoved
methods.Other Events
Other Mac OS-specific events are handled in these ways:
- The suspend and resume operating-system events (type
kODEvtOS
) are passed to your part editor'sHandleEvent
method. Your part should not normally relinquish the selection focus or other foci upon receiving a suspend event.- Disk-inserted events (
kODEvtDisk
) are not distributed to parts.- Mouse-moved events are converted to the OpenDoc user event types
kODEvtMouseEnter
,kODEvtMouseWithin
, andkODEvtMouseLeave
, as described under "Mouse Events"
Propagating Events
A containing part can set a flag in an embedded frame that allows the containing part to receive events not handled by the embedded frame. If your part contains embedded frames with that flag set, yourHandleEvent
method receives the events originally sent to them. OpenDoc sets thepropagated
field in theeventInfo
structure (see page 189) to true when passing a propagated event to your part.Whenever you add a facet to a frame, you can check the state of the flag by calling the frame's
DoesPropagateEvents
method. You can then set or clear the flag by calling the frame'sSetPropagateEvents
method.This is a specialized feature of OpenDoc, not likely to be used by most part editors. You might use it to manipulate embedded selections; for example, you could use tab-key events to allow the user to tab between embedded parts that do not themselves support tabbing or otherwise handle tab-key events.
If you do not set the event-propagating flag for any of your embedded frames, your
HandleEvent
method receives only those embedded-frame events described under "Mouse Events in Embedded Frames"The HandleEvent Method of Your Part Editor
The dispatcher calls your part'sHandleEvent
method to pass it a user event meant for your part. This is the method's interface:
ODBoolean HandleEvent(inout ODEventData event, in ODFrame frame, in ODFacet facet), inout ODEventInfo eventInfo);Your implementation ofHandleEvent
might be similar to this:
Your individual event handlers should function as described in other sections of this chapter. Each should return
- Set the result flag to
kODFalse
.- Obtain the part info data from the frame or facet to which the event was directed, if you have stored relevant information there.
- Execute a
switch
statement with one case for each event type. Pass execution to the appropriate handler for each event type. Set the result flag tokODTrue
if an individual handler handles the event.- Return the result flag as the method result.
kODTrue
toHandleEvent
if it handles an event, andkODFalse
if it does not.
[4] Container parts (parts that can embed other parts) must handle these events.
Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help